package com.why.app;

import com.why.annotaion.RpcScan;
import com.why.annotaion.RpcService;
import com.why.enums.ErrorEnum;
import com.why.exception.RpcException;
import com.why.server.Server;

import com.why.utils.ReflectUtil;
import lombok.extern.slf4j.Slf4j;


import java.util.Set;

/**
 * @program: why-rpc-framework
 * @description:
 * @author: @why
 * @create: 2021-03-17 13:12
 **/
@Slf4j
public class AnnotationServiceScanApplicationContext {


    private Server server;


    public AnnotationServiceScanApplicationContext(Server server) {
        this.server = server;

    }

    /**
     * 完成注解扫描，如果未指明启动类，那就使用反射工具类获取方法栈的栈底，扫描启动类所在的包路径下的所有类
     *
     * @param clazz
     * @return
     */
    public Server scanServicesApplication(Class<?> clazz) {

        Class<?> mainClass = null;

        try {
            if (clazz == null) {
                log.warn("请最好指定启动类的位置！");
                log.info("通过方法栈获取启动类的位置。。。");
                String packageName = ReflectUtil.getStackTrace();
                mainClass = Class.forName(packageName);
            } else {
                mainClass = clazz;
            }

            log.info("开始获取启动类上面的注解");
            if (!mainClass.isAnnotationPresent(RpcScan.class)) {
                throw new RpcException(ErrorEnum.NO_SERVERSCAN_ANNOTATION_ERROR);
            }

            log.info("开始从RpcScan注解上面获取服务提供者位置");
            String packageBase = mainClass.getAnnotation(RpcScan.class).servicesPackageBase();
            if ("".equals(packageBase)) {
                log.info("未指定服务的位置，开始设置扫描启动类父包下面的所有的包");
                String location = mainClass.getCanonicalName();
                packageBase = location.substring(0, location.lastIndexOf("."));
            }
            log.info("服务类的位置是:{}", packageBase);
            Set<Class<?>> services = ReflectUtil.getClasses(packageBase);

            log.info("开始去注册服务。。");

            for (Class<?> service : services) {
                Object obj;
                if (service.isAnnotationPresent(RpcService.class)) {
                    //实例化服务类
                    obj = Class.forName(service.getCanonicalName()).newInstance();
                    String serviceName = service.getAnnotation(RpcService.class).name();
                    /**
                     * 判断该服务是否指定了名字，没有指定，那就使用其接口作为服务的名字
                     * // TODO: 2021/3/17  后期改一波。
                     */
                    if ("".equals(serviceName)) {
                        log.info("服务名称未指定，设置服务的名称为其接口");
                        Class<?>[] interfaces = service.getInterfaces();
                        for (Class<?> anInterface : interfaces) {
                            server.publishService(obj, anInterface.getCanonicalName());
                        }

                    } else {
                        server.publishService(obj, serviceName);
                    }


                }
            }


        } catch (ClassNotFoundException e) {

            log.error("没有发现启动类", e);
        } catch (IllegalAccessException e) {
            log.error("注解扫描的时候访问属性失败", e);

        } catch (InstantiationException e) {
            log.error("实例化服务类失败!", e);
        }


        return server;
    }


}
